Programação Web

Aula 21 - Consumo de API




Helder Jefferson Ferreira da Luz

helder.luz@ifpr.edu.br

Objetivos

  • Entender o que é uma API e como ela funciona no contexto da web.
  • Aprender a fazer requisições HTTP para consumir dados de APIs externas.
  • Compreender o conceito de programação assíncrona em JavaScript.

API (Application Programming Interface)

Interface de Programação de Aplicações.


São padrões estabelecidos por um programa para utilizar os seus recursos, sem precisar entender a implementação interna.


No contexto WEB envolve a requisição a um serviço por meio do protocolo HTTP.

API

API

  • Opa
  • Queridão
  • Gente boa
  • Mestre
  • Fera
  • Patrão
  • Chapa
  • Amigo
  • Chefia
  • Campeão

API

Requisições HTTP

Para realizar requisições HTTP a um servidor há ao menos 3 formas:

  • XMLHttpRequest
  • Fetch
  • Axios

Requisições HTTP

A resposta das requisições não são recebidas imediatamente.


Se a aplicação esperar pela resposta, a aplicação como um todo ficará travada.


Para que não fique esperando, é necessário que a requisição seja assíncrona.

JavaScript Assíncrono

Um código síncrono é executado de forma linear e realizando uma operação por vez.

Se uma função depende do resultado de outra função haverá um tempo de espera, onde o programa ficará parado.

Exemplo: MDN - JavaScript Asynchronous

O JavaScript permite implementar programas assíncronos, onde funções podem executar concomitantemente com outras funções.

JavaScript Assíncrono

A programação assíncrona no JavaScript oferece diversos recursos, dentre eles:

  • Função callback
  • Promises
  • Async / await

Função Callback

A função Callback pode ser síncrona ou assíncrona.

Por padrão ela é síncrona, mas pode ser assíncrona com o uso de funções como o setTimeout.

function callbackAssincrono(callback, parametro) {
  console.log('Início da função callbackAssincrono');
  setTimeout(() => { callback(parametro);  }, 2000);
  console.log('Fim da função callbackAssincrono');
}

function apresentaPessoa(pessoa) {
  console.log(`Olá, meu nome é ${pessoa.nome} e tenho ${pessoa.idade} anos.`);
}

callbackAssincrono(apresentaPessoa, { nome: 'Ana', idade: 30 });

Função Callback e requisição com XMLHttpRequest

function getDados() {
  const url = 'https://jsonplaceholder.typicode.com/todos';

  const req = new XMLHttpRequest();
  req.open('GET', url);
  req.onload = () => {
    const dados = JSON.parse(req.responseText);
    console.log(dados);
  };
  req.send();
}

console.log('Iniciando requisição...');
getDados();
console.log('Requisição enviada...');

Promise (Promessa)

Uma Promise é um objeto que representa a eventual conclusão (ou falha) de uma operação assíncrona.

Promise

Imagine que você pede um café (operação assíncrona). Você recebe uma "promessa" (um pager) de que seu café será entregue. Com o pager, você pode esperar tranquilamente.

  • Sucesso (fulfilled): O pager vibra e você pega seu café.
  • Falha (rejected): O pager informa que a máquina de café quebrou.

A Promise funciona da mesma forma, permitindo que seu código continue executando enquanto aguarda uma resposta da rede.

Promise

Ele representa o eventual sucesso ou falha de uma operação assíncrona, possuindo os métodos:

  • then(<função para sucesso>, <função para falha>)
  • catch(<função para falha>)

Promise - estados

pending (pendente) | fulfilled (realizada) | rejected (rejeitada)

  • pending estado inicial, nem cumprido nem rejeitado.
  • fulfilled significa que a operação foi concluída com sucesso.
  • rejected significa que a operação falhou.

Promise - estados

Promise

Exemplo
promise1
  .then(valor => { return valor + ' and bar'; })
  .then(valor => { return valor + ' and bar again'; })
  .then(valor => { return valor + ' and again'; })
  .then(valor => { return valor + ' and again'; })
  .then(valor => { console.log(valor) })
  .catch(erro => console.log(erro))

Fetch

Permite fazer requisições HTTP assíncronas e utiliza Promise.

Fetch sempre retorna como resultado uma Promise.

fetch(url)
  .then(funcaoSucesso)
  .catch(funcaoFalha)

Fetch

Exemplo
let url = 'https://jsonplaceholder.typicode.com/todos/';

fetch(url)
.then(resposta => resposta.json())
.then(dados => {
    console.log(dados);
})
.catch(erro => {
    console.error(erro);
})

Async e Await

  • async – faz a função retornar uma Promise
  • await – faz a função esperar por uma Promise

Funções que trabalham com Promises precisam do uso do async.

async function getDados() {
  const url = 'https://jsonplaceholder.typicode.com/todos';

  const resposta = await fetch(url);
  const dados = await resposta.json();
  console.log(dados);
}

await getDados();

Async/await - try...catch

Async/await não possuem tratamento de erro, sendo necessário utilizar a estrutura try...catch.

async function getDados() {
  const url = 'https://jsonplaceholder.typicode.com/todos';

  try {
    const resposta = await fetch(url);
    const dados = await resposta.json();
    console.log(dados);
  } catch (erro) {
    console.error('Erro buscando dados:', erro);
  }
}

getDados();

Async/await

Pode-se fazer o tratamento de erro na chamada da função.

async function getDados() {
  const url = 'https://jsonplaceholder.typicode.com/todos';

  const resposta = await fetch(url);
  const dados = await resposta.json();
  console.log(dados);
}

getDados()
.catch((erro) => {
  console.error('Erro buscando dados:', erro);
});

Async/await - Execução sequêncial

O await causa uma sincronização, fazendo com que multiplas promises executem sequencialmente.

Exemplo - função de requisição de dados
async function fetchDados(url) {
  try {
    const resposta = await fetch(url);
    const dados = await resposta.json();
    return dados;
  } catch (erro) {
    console.error('Erro ao buscar dados:', erro);
  }
}

Async/await - Execução sequêncial

Exemplo - requisições sequenciais (baixo desempenho)
async function buscarDadosSequencial() {
  console.time()
  const usuarios = await fetchDados('https://jsonplaceholder.typicode.com/users');
  const postagens = await fetchDados('https://jsonplaceholder.typicode.com/posts');
  const fotos = await fetchDados('https://jsonplaceholder.typicode.com/photos');
  console.timeEnd()
}

buscarDadosSequencial()

Promise.all - Múltiplas promises

O Promise.all() permite realizar várias promises concomitantemente.
Ele recebe um array de Promises e retorna uma única Promise que é resolvida quando todas as Promises do array são resolvidas.

Exemplo - Promise.all para execução concorrente (maior desempenho)
async function buscarDadosEmParalelo() {
  console.time()
  const [usuarios, postagens, fotos] = await Promise.all([
    fetchDados('https://jsonplaceholder.typicode.com/users'),
    fetchDados('https://jsonplaceholder.typicode.com/posts'),
    fetchDados('https://jsonplaceholder.typicode.com/photos')
  ]);
  console.timeEnd()
}

buscarDadosEmParalelo()

APIs de exemplo

https://swapi.dev
https://jsonplaceholder.typicode.com
https://proxyapp.correios.com.br/v1/sro-rastro/ <código rastreio>
https://api.github.com/users/ <usuário>/repos
https://pokeapi.co
https://disneyapi.dev/
https://docs.magicthegathering.io/
https://docs.pokemontcg.io/
https://brasilapi.com.br/docs
https://servicodados.ibge.gov.br/api/docs
https://tcgdex.dev
https://publicapi.dev

Dúvidas? 🤔

Exercícios

  1. Utilizando o console do navegador e a API do GitHub (https://api.github.com), faça:
    1. uma requisição para buscar os dados do seu perfil de usuário.
    2. uma nova requisição para buscar os repositórios públicos do usuário.

Exercícios

  1. Crie uma página com um campo de input para um CEP e um botão "Buscar".
    Ao clicar no botão, utilize a API do ViaCEP (https://viacep.com.br/ws/SEU_CEP/json/) para buscar as informações do endereço.
    Exiba os dados retornados (logradouro, bairro, cidade, etc.) em campos de texto na página.
    Desafio: Adicione uma mensagem de erro amigável se o CEP for inválido ou não for encontrado.

Exercícios

  1. Utilize a PokéAPI (https://pokeapi.co) para buscar uma lista dos 12 primeiros Pokémon.
    1. Para cada Pokémon na lista, faça uma nova requisição para obter os detalhes dele (a API inicial só retorna o nome e a URL dos detalhes).
    2. Crie "cards" para cada Pokémon, exibindo seu nome, imagem e tipo.
    3. Desafio com Promise.all: Em vez de buscar os detalhes de cada Pokémon um por um em sequência, utilize Promise.all para fazer todas as requisições de detalhes em paralelo e otimizar o tempo de carregamento.

Exercícios

  1. Escolha uma API pública. Utilizando a documentação da API, implemente uma página que permita realizar uma requisição à API e apresente os dados retornados na página em formato de tabela, lista, cards ou outro da sua escolha.